﻿/*
* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
*
*/

#include "notificationPlugin.h"

NotificationPlugin::NotificationPlugin()
    : m_pMainWidget(new QWidget)
    , m_pMainWidgetVLayout(new QVBoxLayout())
    , m_pTitleWidget(new QWidget())
    , m_pTitleWidgetHLayout(new QHBoxLayout())
    , m_pNotificationLabel(new QLabel())
    , m_pClearAllNotifyButton(new QPushButton())
    , m_pSettingNotifyButton(new QPushButton())
    , m_pExternalNotifyWidget(new QWidget())
    , m_pExternalNotifyWidgetHLayout(new QHBoxLayout())
    , m_pNotifyQScrollAreaWidget(new ScrollAreaWidget())
    , m_pInsideNotifyWidget(new QWidget())
    , m_pInsideNotifyWidgetVLayout(new QVBoxLayout())
    , m_pMessageCenterLabel(new ExternalLabel())

{
    /* 初始化翻译文件 */
    initTrans();

    /* 初始化gsetting */
    initGsetting();

    /* 初始化界面 */
    initUI();

    /* 初始化相关dbus */
    initDbus();

    /* 初始化动画 */
    initAnimation();

    return;
}

QWidget* NotificationPlugin::centerWidget()
{
    return  m_pMainWidget;
}

/**
 * @brief NotificationPlugin::initTrans
 * 加载翻译文件
 */
void NotificationPlugin::initTrans()
{
    QTranslator *translator = new QTranslator;
    if (translator->load(QLocale(), QLatin1String("ukui-sidebar-notification"), QLatin1String("_"), QLatin1String("/usr/share/ukui-sidebar/ukui-sidebar-notification")))
        QApplication::installTranslator(translator);
    else
        qDebug() << "cannot load translator ukui-sidebar-notification_" << QLocale::system().name() << ".qm!";

    return;
}

void NotificationPlugin::initAnimation()
{
    m_pAnimationHideSidebarNotifition = new QPropertyAnimation(m_pMainWidget, "geometry");
}

/**
 * @brief NotificationPlugin::initDbus
 * 初始化dbus
 */
void NotificationPlugin::initDbus()
{
    //注册dbus接口，接收通知中心发送的通知信息
    m_pNotifyDbus = new NotificationDbus(this);

    //接收快捷操作面板隐藏&显示状态
    connect(SidebarQuickOperationDbus::getInstance(),&SidebarQuickOperationDbus::Sig_quickOperationSignal,this,&NotificationPlugin::onUpdateAnimationData);
}

/**
 * @brief NotificationPlugin::onUpdateAnimationData
 * 更新动画坐标
 * @param arg 动作状态值
 */
void NotificationPlugin::onUpdateAnimationData(QString arg)
{
    // 侧边栏整体高度
    int sidebarHeight = SidebarCoreDbus::getInstance()->getSidebarHeight();

    // 快捷操作面板高度
    int quickOperationPanelHeight = SidebarQuickOperationDbus::getInstance()->getQuickOperationPanelHeight();

    // 快捷面板隐藏的高度
    int quickOperationPanelHideHeight = SidebarQuickOperationDbus::getInstance()->getQuickOperationPanelHideHeight();

    // 快捷面板动画速度
    int animationSpeed = SidebarQuickOperationDbus::getInstance()->getAnimationSpeed();

    if (arg == "SHOW") {
        m_pAnimationHideSidebarNotifition->setDuration(animationSpeed);
        m_pAnimationHideSidebarNotifition->setStartValue(QRect(0, 0, 400, sidebarHeight - quickOperationPanelHideHeight));
        m_pAnimationHideSidebarNotifition->setEndValue(QRect(0, 0, 400, sidebarHeight - quickOperationPanelHeight + SIDEBAR_AND_PANEL_DISTANCE));

    } else if (arg == "HIDE") {
        m_pAnimationHideSidebarNotifition->setDuration(animationSpeed);
        m_pAnimationHideSidebarNotifition->setStartValue(QRect(0, 0, 400, sidebarHeight - quickOperationPanelHeight + SIDEBAR_AND_PANEL_DISTANCE));
        m_pAnimationHideSidebarNotifition->setEndValue(QRect(0, 0, 400, sidebarHeight - quickOperationPanelHideHeight));
    }

    m_pAnimationHideSidebarNotifition->start();
}

/**
 * @brief NotificationPlugin::initUI
 * 初始化UI
 */
void NotificationPlugin::initUI()
{
    /* 初始化界面属性 */
    initAttribute();

    /* 初始化布局 */
    initLayout();

    return;
}

/**
 * @brief NotificationPlugin::initAttribute
 * 初始化界面属性
 */
void NotificationPlugin::initAttribute()
{
    /* 主控件 */
    m_pMainWidget->setObjectName("Notification center");

    /* 通知顶部标签界面 */
    m_pTitleWidget->setObjectName("Title widget");
    m_pTitleWidget->setFixedWidth(390);

    /* 标签-通知中心 */
    m_pNotificationLabel->setObjectName("Notification Center");
    m_pNotificationLabel->setText(QObject::tr("Notification Center"));
    m_pNotificationLabel->setAttribute(Qt::WA_TranslucentBackground);

    /* 清空按钮 */
    m_pClearAllNotifyButton->setObjectName("Clear all");
    m_pClearAllNotifyButton->setText(QObject::tr("Clean"));
    m_pClearAllNotifyButton->setFixedWidth(76);

    connect(m_pClearAllNotifyButton, SIGNAL(clicked()), this, SLOT(onClearAllMessage()));
    m_pClearAllNotifyButton->setVisible(false);
    m_pClearAllNotifyButton->setProperty("needTranslucent",true);
    m_pClearAllNotifyButton->setProperty("useButtonPalette",true);
    m_pClearAllNotifyButton->setFlat(true);

    /* 设置按钮 */
    m_pSettingNotifyButton->setObjectName("Setting");
    m_pSettingNotifyButton->setText(QObject::tr("Set"));
    m_pSettingNotifyButton->setFixedWidth(76);

    connect(m_pSettingNotifyButton, SIGNAL(clicked()), this, SLOT(onCallControlPanel()));
    m_pSettingNotifyButton->setProperty("needTranslucent",true);
    m_pSettingNotifyButton->setProperty("useButtonPalette",true);
    m_pSettingNotifyButton->setFlat(true);

    /* 消息列表部件，用于装消息列表 */
    m_pExternalNotifyWidget->setObjectName("Notify widget");
    m_pExternalNotifyWidget->setParent(m_pMainWidget);

    /* 通知列表 */
    m_pNotifyQScrollAreaWidget->setObjectName("Notify QScroll Area Widget");
    m_pNotifyQScrollAreaWidget->setAttribute(Qt::WA_TranslucentBackground);
    m_pNotifyQScrollAreaWidget->viewport()->setStyleSheet("background-color:transparent;");
    m_pNotifyQScrollAreaWidget->setFrameShape(QFrame::NoFrame);
    m_pNotifyQScrollAreaWidget->setFixedWidth(362);
    m_pNotifyQScrollAreaWidget->setProperty("notUseSlideGesture", true);

    /* 内层通知列表部件 */
    m_pInsideNotifyWidget->setObjectName("InsideNotifyQWidget");
    m_pInsideNotifyWidget->setAttribute(Qt::WA_TranslucentBackground);

    /* 标签-暂无消息通知 */
    m_pMessageCenterLabel->setObjectName("No new notifications");
}

/**
 * @brief NotificationPlugin::initLayout
 * 初始化布局
 */
void NotificationPlugin::initLayout()
{
    /* 插件的总自上而下布局器 */
    m_pMainWidgetVLayout->setContentsMargins(10,16,0,0);
    m_pMainWidgetVLayout->setSpacing(0);

    /* 通知顶部标签界面自左而右布局器 */
    m_pTitleWidgetHLayout->setContentsMargins(14,0,28,0);

    /* 消息列表部件布局 */
    m_pExternalNotifyWidgetHLayout->setContentsMargins(0, 0, 0, 0);
    m_pExternalNotifyWidgetHLayout->setSpacing(4);

    /* 内层通知列表布局 */
    m_pInsideNotifyWidgetVLayout->setContentsMargins(0, 0, 0, 0);
    m_pInsideNotifyWidgetVLayout->setSpacing(4); //此参数是调整两个类型的消息通知间隔的

    QSpacerItem* pHSpacer = new QSpacerItem(300, 10, QSizePolicy::Expanding, QSizePolicy::Fixed);
    QSpacerItem* pMsgListSpacer= new QSpacerItem(5, 16, QSizePolicy::Fixed, QSizePolicy::Fixed);
    QSpacerItem* pVSpacer = new QSpacerItem(10, 1, QSizePolicy::Fixed, QSizePolicy::Expanding);


    /* 通知顶部标签界面布局 */
    m_pTitleWidgetHLayout->addWidget(m_pNotificationLabel, 0, Qt::AlignLeft);
    m_pTitleWidgetHLayout->addSpacerItem(pHSpacer);
    m_pTitleWidgetHLayout->addWidget(m_pClearAllNotifyButton, 0, Qt::AlignRight);
    m_pTitleWidgetHLayout->addWidget(m_pSettingNotifyButton, 0, Qt::AlignRight);
    m_pTitleWidget->setLayout(m_pTitleWidgetHLayout);

    /* 内层通知列表部件布局 */
    m_pInsideNotifyWidgetVLayout->addWidget(m_pMessageCenterLabel, 4, Qt::AlignCenter);
    m_pInsideNotifyWidgetVLayout->addSpacerItem(pVSpacer);
    m_pInsideNotifyWidget->setLayout(m_pInsideNotifyWidgetVLayout);

    /* 外层消息列表界面布局 */
    m_pNotifyQScrollAreaWidget->setWidget(m_pInsideNotifyWidget);
    m_pExternalNotifyWidgetHLayout->addWidget(m_pNotifyQScrollAreaWidget, 0);
    m_pExternalNotifyWidget->setLayout(m_pExternalNotifyWidgetHLayout);

    /* 总体布局 */
    m_pMainWidgetVLayout->addWidget(m_pTitleWidget);
    m_pMainWidgetVLayout->addSpacerItem(pMsgListSpacer);
    m_pMainWidgetVLayout->addWidget(m_pExternalNotifyWidget);
    m_pMainWidget->setLayout(m_pMainWidgetVLayout);
}

/**
 * @brief NotificationPlugin::initGsetting
 * 消息通知的gsetting 初始化
 */
void NotificationPlugin::initGsetting()
{
    NotificationGsetting::getInstance()->setState(false);
    return;
}

/**
 * @brief NotificationPlugin::showNotification
 * 展开时，将通知列表时间刷新
 */
void NotificationPlugin::showNotification()
{
    for(int i = 0; i < m_listAppMsg.count(); i++) {
        AppMsg* pAppMsg = m_listAppMsg.at(i);
        pAppMsg->updateAppPushTime();
    }
}

/**
 * @brief NotificationPlugin::hideNotification
 * 隐藏时，将通知列表折叠
 */
void NotificationPlugin::hideNotification()
{
    for(int i = 0; i < m_listAppMsg.count(); i++){
        AppMsg* pAppMsg = m_listAppMsg.at(i);
        pAppMsg->setAppFold();
    }

}

/**
 * @brief NotificationPlugin::getAppMsgAndIndexByName
 * 按照消息名称寻找此类消息是否存在，存在即返回此类消息指针，不存在即返回指向为空的指针
 * @param strAppName
 * 消息名称
 * @param nIndex
 * 引用，记录在第几个值寻找到此消息
 * @return  AppMsg指针
 */
AppMsg* NotificationPlugin::getAppMsgAndIndexByName(QString strAppName, int& nIndex)
{
    AppMsg* pAppMsg = NULL;
    for(int i = 0; i < m_listAppMsg.count(); i++){
        AppMsg* pTmpAppMsg = m_listAppMsg.at(i);
        if(strAppName == pTmpAppMsg->getAppName()){
            pAppMsg = pTmpAppMsg;
            nIndex = i;
            break;
        }
    }
    return pAppMsg;
}

/**
 * @brief NotificationPlugin::onAddSingleNotify
 * 接受消息函数
 * @param strAppName  消息名称
 * @param strIconPath  图标地址
 * @param strSummary 消息概述
 * @param strBody  消息体
 * @param urlStr  url
 * @param actions  执行动作
 * @param dateTime 时间
 * @param maxNum 最大可存在的消息数量
 * @return 1
 */
uint NotificationPlugin::onAddSingleNotify(QString strAppName, QString strIconPath, QString strSummary,
                                           QString strBody, QString urlStr,  QString actions,
                                           QDateTime dateTime, int maxNum)
{
    qInfo()<<"------------->NotificationPlugin:"<<strAppName<<strIconPath<<strSummary<<strBody<<urlStr<<actions<<dateTime<<maxNum;

    /* 发信号更新侧边栏托盘图标提示 */
    emit Sig_onNewNotification();

    /* 当列表信息为空表明第一次来通知，列表个数为2，一个表面是“没有新通知标签”，一个是底部弹簧 */
    if(0 == m_listAppMsg.count() && 2 == m_pInsideNotifyWidgetVLayout->count()){
        m_pClearAllNotifyButton->show();
        m_pInsideNotifyWidgetVLayout->removeWidget(m_pMessageCenterLabel);
        m_pMessageCenterLabel->setVisible(false);
    }

    int nIndex = -1;
    /* 通过查找m_listAppMsg列表看该app是否已存在 */
    AppMsg* pAppMsg = getAppMsgAndIndexByName(strAppName, nIndex);

    /* 如果不存在，则新建一个AppMsg消息,并且直接置顶 */
    if(NULL == pAppMsg){
        pAppMsg = new AppMsg(this, strAppName);
    } else {
        m_listAppMsg.removeAt(nIndex);
        m_pInsideNotifyWidgetVLayout->removeWidget(pAppMsg);
    }

    /* 更新最大通知数量 */
    pAppMsg->setMaxNumMsg(maxNum);

    /* 在strAppName对应的AppMsg中添加单条信息 */
    pAppMsg->addSingleMsg(strIconPath, strSummary, dateTime, strBody,urlStr, actions);

    int uIndex = m_listAppMsg.count();
    for(int i = m_listAppMsg.count() - 1; i >= 0; i--){
        AppMsg* pTmpAppMsg = m_listAppMsg.at(i);
        if(pAppMsg->getAppPushTime() < pTmpAppMsg->getAppPushTime()){
            break;
        }
        uIndex = i;
    }

    m_listAppMsg.insert(uIndex, pAppMsg);
    m_pInsideNotifyWidgetVLayout->insertWidget(uIndex, pAppMsg);

    /* 新通知，有必要对通知列表更新推送时间 */
    for(int i = 0; i < m_listAppMsg.count(); i++){
        AppMsg* pTmpAppMsg = m_listAppMsg.at(i);
        pTmpAppMsg->updateAppPushTime();
    }

    return 1;
}

/**
 * @brief NotificationPlugin::onClearAppMsg
 * 删除单个应用消息集合
 * @param pAppMsg 需要消除的消息类
 */
void NotificationPlugin::onClearAppMsg(AppMsg* pAppMsg)
{
    int nIndex = m_listAppMsg.indexOf(pAppMsg);
    if(-1 == nIndex){
        qDebug()<<"NotificationPlugin::onClearAppMsg 在通知链表中未找到pSingleMsg指针";
        return;
    }

    m_listAppMsg.removeAt(nIndex);
    m_pInsideNotifyWidgetVLayout->removeWidget(pAppMsg);
    pAppMsg->deleteLater();

    if(0 == m_listAppMsg.count() && 1 == m_pInsideNotifyWidgetVLayout->count()){
        m_pClearAllNotifyButton->hide();
        m_pInsideNotifyWidgetVLayout->insertWidget(0, m_pMessageCenterLabel, 4, Qt::AlignHCenter);
        m_pMessageCenterLabel->setVisible(true);
    }

    return;
}

/**
 * @brief NotificationPlugin::onClearAllMessage
 * 删除全部消息
 */
void NotificationPlugin::onClearAllMessage()
{
    NotificationGsetting::getInstance()->setState(false);

    while (m_listAppMsg.count() > 0)
    {
        AppMsg* pSingleMsg = m_listAppMsg.at(0);
        m_pInsideNotifyWidgetVLayout->removeWidget(pSingleMsg);
        pSingleMsg->deleteLater();
        m_listAppMsg.removeAt(0);
    }

    if(1 == m_pInsideNotifyWidgetVLayout->count()){
        m_pInsideNotifyWidgetVLayout->insertWidget(0, m_pMessageCenterLabel, 4, Qt::AlignHCenter);
        m_pMessageCenterLabel->setVisible(true);
    }

    m_pClearAllNotifyButton->hide();
    //点击清除通知，收集数据
    pointDataStruct pointData;
    pointData.module = NOTIFICATION_CLEAR_BUTTON;
    pointData.function = CLEARALLMESSAGE;
    DataProcess::getInstance()->sendData(pointData);
    return;
}

/**
 * @brief NotificationPlugin::onCloseAppMsg
 * 配置实时关闭通知消息
 * @param strAppName 配置的消息名称
 */
void NotificationPlugin::onCloseAppMsg(QString strAppName)
{
    int nIndex = -1;
    AppMsg* pAppMsg = getAppMsgAndIndexByName(strAppName, nIndex);
    if(NULL != pAppMsg){
        onClearAppMsg(pAppMsg);
    }
}

/**
 * @brief NotificationPlugin::onUpdateAppMaxNum
 * 配置实时更新通知消息最大数
 * @param strAppName 配置的消息名称
 * @param maxNum 最大通知数
 */
void NotificationPlugin::onUpdateAppMaxNum(QString strAppName, int maxNum)
{
    int nIndex = -1;
    AppMsg* pAppMsg = getAppMsgAndIndexByName(strAppName, nIndex);
    if(NULL != pAppMsg) {
        pAppMsg->setMaxNumMsg(maxNum);
        pAppMsg->deleteExceedingMsg();
    }
}

/**
 * @brief NotificationPlugin::onCallControlPanel
 * 调用控制面板-消息通知设置项
 */
void NotificationPlugin::onCallControlPanel()
{
    QStringList args;
    args.append("-m");
    args.append("Notice");
    if(!AppManagerDbus::getInstance()->LaunchAppWithArguments("ukui-control-center.desktop",args)) {
        qWarning()<<"AppManagerDbus 接口无效，采用QProcess启动";
        QProcess p(0);
        p.startDetached("ukui-control-center -m Notice");
        p.waitForStarted();
    }
    //点击设置按钮，收集数据
    pointDataStruct pointData;
    pointData.module = NOTIFICATION_SETTING_BUTTON;
    pointData.function = OPEN_SETTING;
    DataProcess::getInstance()->sendData(pointData);
    return;
}

ExternalLabel::ExternalLabel()
{
    QTranslator *translator = new QTranslator;
    if (translator->load(QLocale(), QLatin1String("ukui-sidebar-notification"), QLatin1String("_"), QLatin1String("/usr/share/ukui-sidebar/ukui-sidebar-notification")))
        QApplication::installTranslator(translator);
    else
        qDebug() << "cannot load translator ukui-sidebar-notification_" << QLocale::system().name() << ".qm!";


    this->setText(QObject::tr("No new notifications"));

}

void ExternalLabel::paintEvent(QPaintEvent *e)
{
    QPainter p(this);
    QRect rect = this->rect();
    p.setRenderHint(QPainter::Antialiasing);  // 反锯齿;
    p.setBrush(QBrush(QColor(255,255,255)));
    p.setOpacity(0);
    p.setPen(Qt::NoPen);
    p.drawRoundedRect(rect,1,1);
    QLabel::paintEvent(e);

}
